'for await...of' ലൂപ്പും കസ്റ്റം അസിങ്ക് ഇറ്ററേറ്റർ ഹെൽപ്പറുകളും ഉപയോഗിച്ച് ജാവാസ്ക്രിപ്റ്റിൽ അസിൻക്രണസ് ഇറ്ററേഷൻ പഠിക്കുക. പ്രായോഗിക ഉദാഹരണങ്ങളിലൂടെ സ്ട്രീം പ്രോസസ്സിംഗും ഡാറ്റാ കൈകാര്യം ചെയ്യലും മെച്ചപ്പെടുത്തുക.
ജാവാസ്ക്രിപ്റ്റ് അസിങ്ക് ഇറ്ററേറ്റർ ഹെൽപ്പർ: ഫോർ ഈച്ച് - സ്ട്രീം പ്രോസസ്സിംഗ് ഇറ്ററേഷൻ
ആധുനിക ജാവാസ്ക്രിപ്റ്റ് ഡെവലപ്മെന്റിന്റെ ഒരു ആണിക്കല്ലാണ് അസിൻക്രണസ് പ്രോഗ്രാമിംഗ്, ഇത് പ്രധാന ത്രെഡിനെ തടസ്സപ്പെടുത്താതെ സമയം എടുക്കുന്ന പ്രവർത്തനങ്ങൾ കൈകാര്യം ചെയ്യാൻ ആപ്ലിക്കേഷനുകളെ പ്രാപ്തരാക്കുന്നു. ECMAScript 2018-ൽ അവതരിപ്പിച്ച അസിങ്ക് ഇറ്ററേറ്ററുകൾ, ഡാറ്റാ സ്ട്രീമുകൾ അസിൻക്രണസായി പ്രോസസ്സ് ചെയ്യുന്നതിനുള്ള ശക്തമായ ഒരു സംവിധാനം നൽകുന്നു. ഈ ബ്ലോഗ് പോസ്റ്റ് അസിങ്ക് ഇറ്ററേറ്ററുകളുടെ ആശയത്തെക്കുറിച്ച് ആഴത്തിൽ ചർച്ച ചെയ്യുകയും സ്ട്രീം പ്രോസസ്സിംഗ് കാര്യക്ഷമമാക്കാൻ ഒരു അസിൻക്രണസ് 'ഫോർ ഈച്ച്' ഹെൽപ്പർ ഫംഗ്ഷൻ എങ്ങനെ നടപ്പിലാക്കാമെന്ന് കാണിക്കുകയും ചെയ്യുന്നു.
അസിങ്ക് ഇറ്ററേറ്ററുകളെ മനസ്സിലാക്കാം
ഒരു അസിങ്ക് ഇറ്ററേറ്റർ എന്നത് AsyncIterator ഇന്റർഫേസിന് അനുയോജ്യമായ ഒരു ഒബ്ജക്റ്റാണ്. ഇത് ഒരു next() മെത്തേഡ് നിർവചിക്കുന്നു, അത് ഒരു പ്രോമിസ് തിരികെ നൽകുന്നു. ഈ പ്രോമിസ് രണ്ട് പ്രോപ്പർട്ടികളുള്ള ഒരു ഒബ്ജക്റ്റായി റിസോൾവ് ചെയ്യുന്നു:
value: ശ്രേണിയിലെ അടുത്ത മൂല്യം.done: ഇറ്ററേറ്റർ പൂർത്തിയായിട്ടുണ്ടോ എന്ന് സൂചിപ്പിക്കുന്ന ഒരു ബൂളിയൻ.
നെറ്റ്വർക്ക് സ്ട്രീമുകൾ, ഫയൽ സിസ്റ്റങ്ങൾ, അല്ലെങ്കിൽ ഡാറ്റാബേസുകൾ പോലുള്ള അസിൻക്രണസ് ഉറവിടങ്ങളിൽ നിന്ന് ഡാറ്റ ഉപയോഗിക്കുന്നതിന് അസിങ്ക് ഇറ്ററേറ്ററുകൾ സാധാരണയായി ഉപയോഗിക്കുന്നു. for await...of ലൂപ്പ് അസിങ്ക് ഇറ്ററബിളുകളിലൂടെ സഞ്ചരിക്കുന്നതിന് സൗകര്യപ്രദമായ ഒരു സിന്റാക്സ് നൽകുന്നു.
ഉദാഹരണം: അസിൻക്രണസായി ഒരു ഫയലിൽ നിന്ന് വായിക്കുന്നത്
പ്രധാന ത്രെഡിനെ തടസ്സപ്പെടുത്താതെ ഒരു വലിയ ഫയൽ ഓരോ വരിയായി വായിക്കേണ്ട ഒരു സാഹചര്യം പരിഗണിക്കുക. ഒരു അസിങ്ക് ഇറ്ററേറ്റർ ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഇത് നേടാനാകും:
const fs = require('fs');
const readline = require('readline');
async function* readFileLines(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
yield line;
}
}
async function processFile(filePath) {
for await (const line of readFileLines(filePath)) {
console.log(`Line: ${line}`);
}
}
// Example usage
processFile('path/to/your/file.txt');
ഈ ഉദാഹരണത്തിൽ, readFileLines ഒരു അസിങ്ക് ജനറേറ്റർ ഫംഗ്ഷനാണ്. ഇത് ഫയലിലെ ഓരോ വരിയും വായിക്കുമ്പോൾ തന്നെ യീൽഡ് ചെയ്യുന്നു. processFile ഫംഗ്ഷൻ for await...of ഉപയോഗിച്ച് വരികളിലൂടെ കടന്നുപോകുകയും ഓരോ വരിയും അസിൻക്രണസായി പ്രോസസ്സ് ചെയ്യുകയും ചെയ്യുന്നു.
ഒരു അസിങ്ക് 'ഫോർ ഈച്ച്' ഹെൽപ്പർ നടപ്പിലാക്കുന്നു
for await...of ലൂപ്പ് ഉപയോഗപ്രദമാണെങ്കിലും, സ്ട്രീമിലെ ഓരോ ഘടകത്തിലും സങ്കീർണ്ണമായ പ്രവർത്തനങ്ങൾ ചെയ്യേണ്ടിവരുമ്പോൾ അത് കൂടുതൽ ദൈർഘ്യമുള്ളതാകാം. ഒരു അസിങ്ക് 'ഫോർ ഈച്ച്' ഹെൽപ്പർ ഫംഗ്ഷന് ഇറ്ററേഷൻ ലോജിക് ഉൾക്കൊള്ളുന്നതിലൂടെ ഈ പ്രക്രിയ ലളിതമാക്കാൻ കഴിയും.
അടിസ്ഥാനപരമായ നിർവ്വഹണം
ഒരു അസിങ്ക് 'ഫോർ ഈച്ച്' ഫംഗ്ഷന്റെ അടിസ്ഥാനപരമായ നിർവ്വഹണം താഴെ നൽകുന്നു:
async function asyncForEach(iterable, callback) {
for await (const item of iterable) {
await callback(item);
}
}
ഈ ഫംഗ്ഷൻ ഒരു അസിങ്ക് ഇറ്ററബിളും ഒരു കോൾബാക്ക് ഫംഗ്ഷനും ആർഗ്യുമെന്റായി എടുക്കുന്നു. ഇത് for await...of ഉപയോഗിച്ച് ഇറ്ററബിളിലൂടെ സഞ്ചരിക്കുകയും ഓരോ ഇനത്തിനും കോൾബാക്ക് ഫംഗ്ഷൻ വിളിക്കുകയും ചെയ്യുന്നു. അടുത്ത ഇനത്തിലേക്ക് പോകുന്നതിന് മുമ്പ് കോൾബാക്ക് ഫംഗ്ഷന്റെ പൂർത്തീകരണത്തിനായി കാത്തിരിക്കണമെങ്കിൽ അതും അസിൻക്രണസ് ആയിരിക്കണം.
ഉദാഹരണം: ഒരു API-യിൽ നിന്നുള്ള ഡാറ്റ പ്രോസസ്സ് ചെയ്യൽ
നിങ്ങൾ ഒരു API-യിൽ നിന്ന് ഡാറ്റ എടുക്കുകയാണെന്ന് കരുതുക, അത് ഇനങ്ങളുടെ ഒരു സ്ട്രീം നൽകുന്നു. ഓരോ ഇനവും വരുമ്പോൾ തന്നെ പ്രോസസ്സ് ചെയ്യാൻ നിങ്ങൾക്ക് അസിങ്ക് 'ഫോർ ഈച്ച്' ഹെൽപ്പർ ഉപയോഗിക്കാം:
async function* fetchDataStream(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
return;
}
// Assuming the API returns JSON chunks
const chunk = decoder.decode(value);
const items = JSON.parse(`[${chunk.replace(/\}\{/g, '},{')}]`); //Split chunks into valid json array
for(const item of items){
yield item;
}
}
} finally {
reader.releaseLock();
}
}
async function processItem(item) {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Processing item: ${JSON.stringify(item)}`);
}
async function main() {
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEach(fetchDataStream(apiUrl), processItem);
console.log('Finished processing data.');
}
// Example usage
main();
ഈ ഉദാഹരണത്തിൽ, fetchDataStream API-യിൽ നിന്ന് ഡാറ്റ എടുക്കുകയും ഓരോ ഇനവും ലഭിക്കുമ്പോൾ തന്നെ യീൽഡ് ചെയ്യുകയും ചെയ്യുന്നു. processItem ഫംഗ്ഷൻ ഓരോ ഇനത്തിലും ഒരു അസിൻക്രണസ് പ്രവർത്തനം അനുകരിക്കുന്നു. asyncForEach ഹെൽപ്പർ പിന്നീട് ഇറ്ററേഷനും പ്രോസസ്സിംഗ് ലോജിക്കും ലളിതമാക്കുന്നു.
മെച്ചപ്പെടുത്തലുകളും പരിഗണനകളും
പിശകുകൾ കൈകാര്യം ചെയ്യൽ (Error Handling)
അസിൻക്രണസ് ഇറ്ററേഷൻ സമയത്ത് ഉണ്ടാകാനിടയുള്ള പിശകുകൾ കൈകാര്യം ചെയ്യേണ്ടത് അത്യാവശ്യമാണ്. ഒഴിവാക്കലുകൾ കണ്ടെത്താനും കൈകാര്യം ചെയ്യാനും നിങ്ങൾക്ക് കോൾബാക്ക് ഫംഗ്ഷൻ ഒരു try...catch ബ്ലോക്കിൽ ഉൾപ്പെടുത്താം:
async function asyncForEach(iterable, callback) {
for await (const item of iterable) {
try {
await callback(item);
} catch (error) {
console.error(`Error processing item: ${item}`, error);
// You can choose to re-throw the error or continue processing
}
}
}
കൺകറൻസി നിയന്ത്രണം (Concurrency Control)
സ്ഥിരമായി, അസിങ്ക് 'ഫോർ ഈച്ച്' ഹെൽപ്പർ ഇനങ്ങൾ ക്രമാനുഗതമായി പ്രോസസ്സ് ചെയ്യുന്നു. നിങ്ങൾക്ക് ഇനങ്ങൾ ഒരേസമയം പ്രോസസ്സ് ചെയ്യണമെങ്കിൽ, ഒരേസമയം നടക്കുന്ന പ്രവർത്തനങ്ങളുടെ എണ്ണം പരിമിതപ്പെടുത്താൻ നിങ്ങൾക്ക് ഒരു പ്രോമിസ് പൂൾ ഉപയോഗിക്കാം:
async function asyncForEachConcurrent(iterable, callback, concurrency) {
const executing = [];
for await (const item of iterable) {
const p = callback(item).then(() => executing.splice(executing.indexOf(p), 1));
executing.push(p);
if (executing.length >= concurrency) {
await Promise.race(executing);
}
}
await Promise.all(executing);
}
async function processItem(item) {
// Simulate an asynchronous operation
await new Promise(resolve => setTimeout(resolve, 100));
console.log(`Processing item: ${JSON.stringify(item)}`);
}
async function main() {
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEachConcurrent(fetchDataStream(apiUrl), processItem, 5); // Concurrency of 5
console.log('Finished processing data.');
}
ഈ ഉദാഹരണത്തിൽ, asyncForEachConcurrent ഒരേസമയം നടക്കുന്ന കോൾബാക്ക് എക്സിക്യൂഷനുകളുടെ എണ്ണം നിർദ്ദിഷ്ട കൺകറൻസി ലെവലിലേക്ക് പരിമിതപ്പെടുത്തുന്നു. വലിയ ഡാറ്റാ സ്ട്രീമുകളുമായി പ്രവർത്തിക്കുമ്പോൾ ഇത് പ്രകടനം മെച്ചപ്പെടുത്താൻ സഹായിക്കും.
റദ്ദാക്കൽ (Cancellation)
ചില സാഹചര്യങ്ങളിൽ, ഇറ്ററേഷൻ പ്രക്രിയ നേരത്തെ റദ്ദാക്കേണ്ടതായി വന്നേക്കാം. ഒരു AbortController ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഇത് നേടാനാകും:
async function asyncForEach(iterable, callback, signal) {
for await (const item of iterable) {
if (signal && signal.aborted) {
console.log('Iteration aborted.');
return;
}
await callback(item);
}
}
async function main() {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => {
controller.abort(); // Abort after 2 seconds
}, 2000);
const apiUrl = 'https://api.example.com/data'; // Replace with your API endpoint
await asyncForEach(fetchDataStream(apiUrl), processItem, signal);
console.log('Finished processing data.');
}
ഈ ഉദാഹരണത്തിൽ, asyncForEach ഫംഗ്ഷൻ ഓരോ ഇറ്ററേഷനും മുമ്പായി signal.aborted പ്രോപ്പർട്ടി പരിശോധിക്കുന്നു. സിഗ്നൽ റദ്ദാക്കപ്പെട്ടാൽ, ഇറ്ററേഷൻ നിർത്തുന്നു.
യഥാർത്ഥ ലോകത്തിലെ ഉപയോഗങ്ങൾ
അസിങ്ക് ഇറ്ററേറ്ററുകളും അസിങ്ക് 'ഫോർ ഈച്ച്' ഹെൽപ്പറും പലതരം യഥാർത്ഥ ലോക സാഹചര്യങ്ങളിൽ പ്രയോഗിക്കാൻ കഴിയും:
- ഡാറ്റാ പ്രോസസ്സിംഗ് പൈപ്പ്ലൈനുകൾ: ഡാറ്റാബേസുകളിൽ നിന്നോ ഫയൽ സിസ്റ്റങ്ങളിൽ നിന്നോ വലിയ ഡാറ്റാസെറ്റുകൾ പ്രോസസ്സ് ചെയ്യുന്നു.
- തത്സമയ ഡാറ്റാ സ്ട്രീമുകൾ: വെബ് സോക്കറ്റുകൾ, മെസേജ് ക്യൂകൾ, അല്ലെങ്കിൽ സെൻസർ നെറ്റ്വർക്കുകൾ എന്നിവയിൽ നിന്നുള്ള ഡാറ്റ കൈകാര്യം ചെയ്യുന്നു.
- API ഉപയോഗം: ഇനങ്ങളുടെ സ്ട്രീമുകൾ നൽകുന്ന API-കളിൽ നിന്ന് ഡാറ്റ എടുക്കുകയും പ്രോസസ്സ് ചെയ്യുകയും ചെയ്യുന്നു.
- ചിത്ര-വീഡിയോ പ്രോസസ്സിംഗ്: വലിയ മീഡിയ ഫയലുകൾ ഭാഗങ്ങളായി പ്രോസസ്സ് ചെയ്യുന്നു.
- ലോഗ് വിശകലനം: വലിയ ലോഗ് ഫയലുകൾ ഓരോ വരിയായി വിശകലനം ചെയ്യുന്നു.
ഉദാഹരണം - അന്താരാഷ്ട്ര സ്റ്റോക്ക് ഡാറ്റ: വിവിധ അന്താരാഷ്ട്ര എക്സ്ചേഞ്ചുകളിൽ നിന്ന് തത്സമയ സ്റ്റോക്ക് വിലകൾ ലഭ്യമാക്കുന്ന ഒരു ആപ്ലിക്കേഷൻ പരിഗണിക്കുക. ഡാറ്റ സ്ട്രീം ചെയ്യാൻ ഒരു അസിങ്ക് ഇറ്ററേറ്റർ ഉപയോഗിക്കാം, കൂടാതെ ഓരോ വിലയും പ്രോസസ്സ് ചെയ്യാനും ഉപയോക്തൃ ഇന്റർഫേസ് ഏറ്റവും പുതിയ വിലകൾ ഉപയോഗിച്ച് അപ്ഡേറ്റ് ചെയ്യാനും ഒരു അസിങ്ക് 'ഫോർ ഈച്ച്' സഹായിക്കും. താഴെ പറയുന്ന കമ്പനികളുടെ നിലവിലെ സ്റ്റോക്ക് നിരക്കുകൾ പ്രദർശിപ്പിക്കാൻ ഇത് ഉപയോഗിക്കാം:
- ടെൻസെന്റ് (ചൈന): ഒരു പ്രമുഖ അന്താരാഷ്ട്ര സാങ്കേതിക കമ്പനിയുടെ സ്റ്റോക്ക് ഡാറ്റ ലഭ്യമാക്കുന്നു
- ടാറ്റ കൺസൾട്ടൻസി സർവീസസ് (ഇന്ത്യ): ഒരു പ്രമുഖ ഐടി സേവന കമ്പനിയിൽ നിന്നുള്ള സ്റ്റോക്ക് അപ്ഡേറ്റുകൾ പ്രദർശിപ്പിക്കുന്നു
- സാംസങ് ഇലക്ട്രോണിക്സ് (ദക്ഷിണ കൊറിയ): ഒരു ആഗോള ഇലക്ട്രോണിക്സ് നിർമ്മാതാവിന്റെ സ്റ്റോക്ക് നിരക്കുകൾ കാണിക്കുന്നു
- ടൊയോട്ട മോട്ടോർ കോർപ്പറേഷൻ (ജപ്പാൻ): ഒരു അന്താരാഷ്ട്ര വാഹന നിർമ്മാതാവിന്റെ സ്റ്റോക്ക് വിലകൾ നിരീക്ഷിക്കുന്നു
ഉപസംഹാരം
ജാവാസ്ക്രിപ്റ്റിൽ ഡാറ്റാ സ്ട്രീമുകൾ അസിൻക്രണസായി പ്രോസസ്സ് ചെയ്യുന്നതിനുള്ള ശക്തവും ലളിതവുമായ ഒരു മാർഗ്ഗം അസിങ്ക് ഇറ്ററേറ്ററുകളും അസിങ്ക് 'ഫോർ ഈച്ച്' ഹെൽപ്പറും നൽകുന്നു. ഇറ്ററേഷൻ ലോജിക് ഉൾക്കൊള്ളുന്നതിലൂടെ, നിങ്ങൾക്ക് നിങ്ങളുടെ കോഡ് ലളിതമാക്കാനും, വായനാക്ഷമത മെച്ചപ്പെടുത്താനും, നിങ്ങളുടെ ആപ്ലിക്കേഷനുകളുടെ പ്രകടനം വർദ്ധിപ്പിക്കാനും കഴിയും. പിശകുകൾ കൈകാര്യം ചെയ്യുക, കൺകറൻസി നിയന്ത്രിക്കുക, റദ്ദാക്കൽ പ്രവർത്തനക്ഷമമാക്കുക എന്നിവയിലൂടെ, നിങ്ങൾക്ക് കരുത്തുറ്റതും വികസിപ്പിക്കാവുന്നതുമായ അസിൻക്രണസ് ഡാറ്റാ പ്രോസസ്സിംഗ് പൈപ്പ്ലൈനുകൾ നിർമ്മിക്കാൻ കഴിയും.